#ifndef __loghpp__
#define __loghpp__

#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <ctime>
#include <stdarg.h>
#include <fstream>
#include"APILock.hpp"
using namespace std;
bool isfileout = false;
const char *name = "log.txt";
pthread_mutex_t loglock;
// c99新特性__VA_ARGS__，适应可变参数...,//加##是为了防止可变参数
#define LOG(grade, format, ...)                                                  \
    do                                                                           \
    {                                                                            \
        logmessage(__FILE__, __LINE__, isfileout, grade, format, ##__VA_ARGS__); \
    } while (0); // 加个do while(0)可以保证替换多个语句,否则只能替换一个语句

// 日志的等级
enum flag
{
    DEBUG = 0,
    INFO,
    WARN,
    ERROR
};

void coutfile()
{
    isfileout = true;
}

void coutscreen()
{
    isfileout = false;
}

void GetCurrTime(string &ret)
{
    time_t curr_time = time(nullptr);          // 得到当前时间
    struct tm *f_time = localtime(&curr_time); // 转换为年月日
    if (f_time == nullptr)
        ret = "no_time";
    else
    {
        ret = to_string(f_time->tm_year + 1900) + '-' + to_string(f_time->tm_mon + 1) 
        + '-' + to_string(f_time->tm_mday) + ' ' + to_string(f_time->tm_hour) 
        + ':' + to_string(f_time->tm_min) + ':' + to_string(f_time->tm_sec);
    }
}

string GetLogGrade(int grade)
{
    switch (grade)
    {
    case DEBUG:
        return "DEBUG";
    case INFO:
        return "INFO";
    case WARN:
        return "WARN";
    case ERROR:
        return "ERROR";

    default:
        return "Nongrade";
    }
}

void logmessage(const char *filename, int line, bool Isfilout, int grade, const char *format, ...)
{
    int selfpid = getpid(); // 进程pid
    // 处理时间
    string t_time;
    GetCurrTime(t_time);
    // 处理日志等级
    string s_grade = GetLogGrade(grade);
    // 处理可变参数
    va_list arg;           // 定义一个可变参数列表
    va_start(arg, format); // format是为了告诉可变参数列表的前一个位置，以找到列表
    char buffer[1024];
    vsnprintf(buffer, sizeof(buffer), format, arg); // 适用于那些需要处理可变数量参数的场景,以空字符 \0 结尾
    va_end(arg);
    // 格式化输出
    string arge = '[' + to_string(selfpid) + ']' + '[' + "filename:" + filename + ']' 
    + '[' + "line:" + to_string(line) + ']' + '[' + s_grade + ']' 
    + '[' + "content:" + t_time + ']' + buffer 
    + '\n';
    //初始化lock
    pthread_mutex_init(&loglock,nullptr);
    APIlock lock(&loglock);
    if (!Isfilout)
    {
        cout << arge;
    }
    else
    {
        // 在log.txt输入
        ofstream out(name,ios_base::app);//以追加的方式打开
        if(out.is_open())
        {
            out<<arge;
            out.close();
        }
    }
}

#endif